﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Security.Cryptography;
using System.IO;

namespace shopsoft.Common.Security
{
    /// <summary>
    /// DES加密解密类
    /// </summary>
    public sealed class Des
    {
        private Des() { }

        #region Encrypt/Decrypt

        /// <summary>
        /// 创建一个用于进行DES加密/解密的服务提供者实例
        /// </summary>
        /// <param name="key">一个字符串,代表加密/解密时使用的字符串</param>
        /// <returns>返回生成的可用于进行DES加密/解密的服务提供者实例</returns>
        private static DESCryptoServiceProvider CreateDESProvider(string key)
        {
            // 修正可能无效的密钥
            if (key.Length == 0)
                key = new PubConfig().DesDefaultKey;

            // 使用Key的哈西值填充des中的Key和IV
            byte[] keyByteArray = Encoding.Default.GetBytes(key);
            SHA1 ha = new SHA1Managed();
            byte[] hb = ha.ComputeHash(keyByteArray);
            byte[] sKey = new byte[8];
            byte[] sIV = new byte[8];

            for (int i = 0; i < 8; i++)
            {
                sKey[i] = hb[i];
                sIV[i] = hb[i + 8];
            }

            // 生成DES加密/解密服务提供者
            DESCryptoServiceProvider des = new DESCryptoServiceProvider { Key = sKey, IV = sIV };

            // 返回DES加密/解密服务提供者
            return des;
        }

        /// <summary>
        /// 使用指定密钥加密字符串
        /// </summary>
        /// <param name="source">要加密字符串的原文</param>
        /// <param name="key">加密密钥</param>
        /// <returns></returns>
        public static string Encrypt(string source, string key)
        {
            // 准备用于加密的原文
            byte[] inputByteArray = Encoding.Default.GetBytes(source);

            // 生成用于进行DES加密/解密的服务提供者实例
            DESCryptoServiceProvider des = CreateDESProvider(key);

            // 在内存中进行加密/解密
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            StringBuilder ret = new StringBuilder();
            foreach (byte b in ms.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }
            cs.Close();
            ms.Close();

            // 输出结果
            return ret.ToString();
        }

        /// <summary>
        /// 使用默认密钥加密字符串
        /// </summary>
        /// <param name="source">要加密字符串的原文</param>
        /// <returns></returns>
        public static string Encrypt(string source)
        {
            return Encrypt(source, new PubConfig().DesDefaultKey);
        }

        /// <summary>
        /// 使用指定密钥解密字符串
        /// </summary>
        /// <param name="source">要解密字符串的原文</param>
        /// <param name="key">解密密钥</param>
        /// <returns></returns>
        public static string Decrypt(string source, string key)
        {
            // 还原要解密的字符串
            byte[] inputByteArray = new byte[source.Length / 2];
            for (int x = 0; x < source.Length / 2; x++)
            {
                int i = (Convert.ToInt32(source.Substring(x * 2, 2), 16));
                inputByteArray[x] = (byte)i;
            }

            // 生成用于进行DES加密/解密的服务提供者实例
            DESCryptoServiceProvider des = CreateDESProvider(key);

            // 进行DES解密操作
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            // 返回解密过的数据
            return Encoding.Default.GetString(ms.ToArray());
        }

        /// <summary>
        /// 使用默认密钥解密字符串
        /// </summary>
        /// <param name="source">要解密字符串的原文</param>
        /// <returns></returns>
        public static string Decrypt(string source)
        {
            return Decrypt(source, new PubConfig().DesDefaultKey);
        }

        #endregion Encrypt/Decrypt
    }
}
